package org.yinweichen.llm_dataset_backend.service.impl;

import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import jakarta.persistence.criteria.Subquery;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.yinweichen.llm_dataset_backend.DTO.QuestionSearchRequest;
import org.yinweichen.llm_dataset_backend.DTO.StandardQuestionCreateDTO;
import org.yinweichen.llm_dataset_backend.DTO.StandardQuestionUpdateDTO;
import org.yinweichen.llm_dataset_backend.entity.OriginalQuestion;
import org.yinweichen.llm_dataset_backend.entity.StandardAnswer;
import org.yinweichen.llm_dataset_backend.entity.StandardQuestion;
import org.yinweichen.llm_dataset_backend.entity.StandardQuestionId;
import org.yinweichen.llm_dataset_backend.repository.OriginalQuestionRepository;
import org.yinweichen.llm_dataset_backend.repository.StandardQuestionRepository;
import org.yinweichen.llm_dataset_backend.service.StandardQuestionService;
import org.yinweichen.llm_dataset_backend.util.IdGenerator;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
@RequiredArgsConstructor
public class StandardQuestionServiceImpl implements StandardQuestionService {

    private final StandardQuestionRepository questionRepository;
    private final OriginalQuestionRepository originalQuestionRepository;
    private final IdGenerator idGenerator;

    @Override
    @Transactional
    public ResponseEntity<StandardQuestion> create(StandardQuestionCreateDTO dto) {
        try {
            StandardQuestion question = new StandardQuestion();
            question.setId(idGenerator.generateUniqueIdForStandardQuestion());
            question.setVersion(dto.originalQuestionVersion());
            question.setQuestion(dto.question());
            question.setUpdateTime(new Date());
            question.setCategory(dto.category());

            if (dto.originalQuestionId() != null) {
                OriginalQuestion original = originalQuestionRepository
                    .findByIdAndVersion(
                        dto.originalQuestionId(),
                        dto.originalQuestionVersion()
                    )
                    .orElseThrow(() -> new IllegalArgumentException("关联的OriginalQuestion不存在"));
                question.setOriginalQuestion(original);
            }

            StandardQuestion savedQuestion = questionRepository.save(question);
            return ResponseEntity.status(HttpStatus.CREATED).body(savedQuestion);
        } catch (IllegalArgumentException e) {
            return ResponseEntity.badRequest().build();
        } catch (Exception e) {
            return ResponseEntity.internalServerError().build();
        }
    }

    @Override
    @Transactional
    public void update(StandardQuestionUpdateDTO dto) {
        questionRepository.update(
                dto.question(),
                dto.category(),
                dto.id(),
                dto.version()
        );
    }

    @Override
    @Transactional
    public ResponseEntity<Void> switchActiveStatus(Long id,String version) {
        try {
            StandardQuestion question = getById(id, version).getBody();

            if (question.getActive()) {
                questionRepository.inactivate(id,version);
            } else {
                questionRepository.activate(id,version);
            }

            return ResponseEntity.noContent().build();
        } catch (IllegalArgumentException e) {
            return ResponseEntity.notFound().build();
        } catch (Exception e) {
            return ResponseEntity.internalServerError().build();
        }
    }

    @Override
    public ResponseEntity<StandardQuestion> getById(Long id, String version) {
        try {
            StandardQuestion question = questionRepository.findById(new StandardQuestionId(id, version))
                .orElseThrow(() -> new IllegalArgumentException("问题不存在"));
            return ResponseEntity.ok(question);
        } catch (IllegalArgumentException e) {
            return ResponseEntity.notFound().build();
        } catch (Exception e) {
            return ResponseEntity.internalServerError().build();
        }
    }

    @Override
    public ResponseEntity<List<StandardQuestion>> findAllActive(String version, int page, int size) {
        try {
            List<StandardQuestion> questions = questionRepository.findActiveQuestions(
                version,
                org.springframework.data.domain.PageRequest.of(page, size)
            );
            return ResponseEntity.ok(questions);
        } catch (Exception e) {
            return ResponseEntity.internalServerError().build();
        }
    }

    @Override
    public ResponseEntity<List<StandardQuestion>> findInactiveQuestions(String version, int page, int size) {
        try {
            List<StandardQuestion> questions = questionRepository.findInactiveQuestions(
                version,
                org.springframework.data.domain.PageRequest.of(page, size)
            );
            return ResponseEntity.ok(questions);
        } catch (Exception e) {
            return ResponseEntity.internalServerError().build();
        }
    }

    @Override
    public ResponseEntity<List<StandardQuestion>> findByOriginalQuestion(Long originalId, String version) {
        try {
            List<StandardQuestion> questions = questionRepository.findByOriginalQuestionIdAndOriginalQuestionVersion(originalId, version);
            return ResponseEntity.ok(questions);
        } catch (Exception e) {
            return ResponseEntity.internalServerError().build();
        }
    }

    @Override
    public ResponseEntity<List<StandardQuestion>> findQuestionsWithoutAnswers(String version, int page, int size){
        try {
            List<StandardQuestion> questions = questionRepository.findQuestionsWithoutAnswers(
                version,
                org.springframework.data.domain.PageRequest.of(page, size)
            );
            return ResponseEntity.ok(questions);
        } catch (Exception e) {
            return ResponseEntity.internalServerError().build();
        }
    }

    @Override
    public Long countQuestionsWithoutAnswers(String version) {
        try {
            return questionRepository.countQuestionsWithoutAnswers(version);
        } catch (Exception e) {
            return 0L;
        }
    }

    @Override
    public Long countActiveQuestions(String version) {
        try {
            return questionRepository.countActiveQuestions(version);
        } catch (Exception e) {
            return 0L;
        }
    }

    @Override
    public Long countInactiveQuestions(String version) {
        try {
            return questionRepository.countInactiveQuestions(version);
        } catch (Exception e) {
            return 0L;
        }
    }

    @Override
    public ResponseEntity<Page<StandardQuestion>> searchQuestions(QuestionSearchRequest searchRequest, int page, int size) {
        try {
            Specification<StandardQuestion> spec = (root, query, criteriaBuilder) -> {
                List<Predicate> predicates = new ArrayList<>();

                // 版本号筛选
                predicates.add(criteriaBuilder.equal(root.get("version"), searchRequest.getVersionId()));

                // 标签筛选
                if (searchRequest.getTags() != null && !searchRequest.getTags().isEmpty()) {
                    // 获取包含所有指定标签的问题ID和版本
                    List<Long> questionIdsWithTags = questionRepository.findQuestionsWithAllTags(
                        searchRequest.getVersionId(),
                        searchRequest.getTags(),
                        searchRequest.getTags().size()
                    );

                    // 添加ID筛选条件
                    if (!questionIdsWithTags.isEmpty()) {
                        predicates.add(root.get("id").in(questionIdsWithTags));
                    } else {
                        // 如果没有匹配的问题，返回空结果
                        predicates.add(criteriaBuilder.equal(root.get("id"), -1L));
                    }
                }

                // 是否活跃筛选
                if (searchRequest.getIsActive() != null) {
                    predicates.add(criteriaBuilder.equal(root.get("active"), searchRequest.getIsActive()));
                }

                // 关键词筛选
                if (searchRequest.getKeyword() != null && !searchRequest.getKeyword().isEmpty()) {
                    predicates.add(criteriaBuilder.like(root.get("question"), "%" + searchRequest.getKeyword() + "%"));
                }

                // 分类筛选
                if (searchRequest.getCategory() != null && !searchRequest.getCategory().isEmpty()) {
                    predicates.add(criteriaBuilder.equal(root.get("category"), searchRequest.getCategory()));
                }
                // 是否有标准答案筛选
                if (searchRequest.getHasStandardAnswer() != null) {
                    Subquery<Long> answerSubquery = query.subquery(Long.class);
                    Root<StandardAnswer> answerRoot = answerSubquery.from(StandardAnswer.class);
                    answerSubquery.select(answerRoot.get("questionId"))
                            .where(
                                    criteriaBuilder.equal(answerRoot.get("version"), root.get("version")),
                                    criteriaBuilder.equal(answerRoot.get("questionId"), root.get("id"))
                            );

                    if (searchRequest.getHasStandardAnswer()) {
                        predicates.add(criteriaBuilder.exists(answerSubquery));
                    } else {
                        predicates.add(criteriaBuilder.not(criteriaBuilder.exists(answerSubquery)));
                    }
                }

                return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
            };

            Page<StandardQuestion> questions = questionRepository.findAll(spec, PageRequest.of(page, size));



            return ResponseEntity.ok(questions);
        } catch (Exception e) {
            return ResponseEntity.internalServerError().build();
        }
    }

    @Override
    public List<String> getAllCategories(String version) {
        return questionRepository.findDistinctCategoriesByVersion(version);
    }

    @Override
    @Transactional
    public void setQuestionCategory(Long questionId, String version, String category) {
        questionRepository.updateCategory(questionId, version, category);
    }

}
